package com.tbit.uqbike.client.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tbit.uqbike.client.constant.AccountConfigExtConstant;
import com.tbit.uqbike.client.constant.CommonConstant;
import com.tbit.uqbike.client.constant.InvoiceRecordConstant;
import com.tbit.uqbike.client.dao.core.InvoiceRecordDao;
import com.tbit.uqbike.client.exception.BaseException;
import com.tbit.uqbike.client.pojo.*;
import com.tbit.uqbike.client.pojo.autoInvoice.AutoInvoiceBody;
import com.tbit.uqbike.client.pojo.autoInvoice.OrderDetail;
import com.tbit.uqbike.client.pojo.autoInvoice.RedChongBody;
import com.tbit.uqbike.client.pojo.autoInvoice.SpExt;
import com.tbit.uqbike.client.pojo.vo.NoticeVO;
import com.tbit.uqbike.client.service.*;
import com.tbit.uqbike.client.util.DateTimeUtil;
import com.tbit.uqbike.client.util.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;


@Slf4j
@Service
public class AutoInvoiceServiceImpl implements AutoInvoiceService {

    ThreadLocal<Integer> threadReDoTime = new ThreadLocal<>();

    @Autowired
    private InvoiceRecordDao invoiceRecordDao;
    @Autowired
    private InvoiceConfigService invoiceConfigService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private SendInvoiceLogService sendInvoiceLogService;
    @Autowired
    private NoticeService noticeService;
    @Value("${autoInvoice.login.url:https://shanghu.shuzutech.com/login}")
    private String loginUrl;
    @Value("${autoInvoice.spbm:3040502019900000000}")
    private String spbm;

    //自动开票的token的缓存key
    private static String AUTO_INVOICE_KEY = AccountConfigExtConstant.AUTO_INVOICE + ":";

    /**
     * @description: 自动开票
     * @author: mo.shanyong
     * @date: 2025/4/2 14:27
     * @param: invoiceRecord
     */
    @Override
    public void autoInvoicing(InvoiceRecord invoiceRecord) {
        //获取品牌的开票配置信息
        InvoiceConfig invoiceConfig = invoiceConfigService.queryByBrandId(invoiceRecord.getBrandId());
        if (Objects.isNull(invoiceConfig)){
            log.info("未配置自动开票：brandId:{}",invoiceRecord.getBrandId());
            return;
        }
        log.info("品牌的自动开票配置：{}",JSON.toJSONString(invoiceConfig));
        //开票
        this.doInvoicing(invoiceRecord,invoiceConfig);
    }
    /**
     * @description: 开票操作
     * @author: mo.shanyong
     * @date: 2025/4/2 17:37
     * @param: invoiceConfig
     */
    private void doInvoicing(InvoiceRecord invoiceRecord,InvoiceConfig invoiceConfig){
        //获取token
        String token = this.getAutoInvoicingToken(invoiceConfig);
        if (StringUtils.isBlank(token)){
            log.info("获取自动开票token失败");
            //记录开票失败原因备注,同时发送公告给品牌人员
            this.updateRemarkAndSendNotice(invoiceRecord.getId(),null,"开票鉴权失败",invoiceConfig);
            return;
        }
        //组装开票请求数据
        AutoInvoiceBody autoInvoiceBody = this.getAutoInvoiceBody(invoiceRecord, invoiceConfig);
        //获取开发票请求参数字符串
        String invoiceRequestBody = this.getInvoiceRequestBody(autoInvoiceBody, invoiceConfig, InvoiceRecordConstant.INVOICE_API_INVOICING_SERVICE_ID);
        //发送请求
        this.invoiceRequest(invoiceRecord,invoiceConfig,invoiceRequestBody,token);
    }
    /**
     * @description: 发送开票请求
     * @author: mo.shanyong
     * @date: 2025/4/3 11:53
     * @param: invoiceRecord 发票信息
     * @param: invoiceConfig 发票配置
     * @param: invoiceRequestBody 开票参数
     * @param: token
     */
    private void invoiceRequest(InvoiceRecord invoiceRecord,InvoiceConfig invoiceConfig,String invoiceRequestBody,String token){
        log.info("invoiceRequestBody:{}",invoiceRequestBody);
        Map<String, String> headers = this.getRequestHead(invoiceRecord.getApplyTime(), invoiceRequestBody, token, invoiceConfig.getAppId());
        String response = HttpUtil.httpRequest(invoiceConfig.getRequestHost() + InvoiceRecordConstant.INVOICE_API_INVOICING_URI, invoiceRequestBody, headers);
        if (StringUtils.isBlank(response)){
            log.info("开票失败，返回结果为空");
            return;
        }
        JSONObject jsonObject = JSON.parseObject(response);
        log.info("申请开票返回结果：{}",JSON.toJSONString(jsonObject));
        Object code = jsonObject.get("code");
        if (Objects.isNull(code) || !Objects.equals(Integer.parseInt(code.toString()), CommonConstant.AUTO_INVOICE_REQUEST_SUCCESS_CODE)){
            log.info("开票失败，返回结果：{}",JSON.toJSONString(jsonObject));
            //判断是否是因为token过期导致的失败
            if (this.reDo(Integer.parseInt(code.toString()))){
                threadReDoTime.set(1);
                redisService.del( AUTO_INVOICE_KEY + invoiceConfig.getBrandId());
                doInvoicing(invoiceRecord,invoiceConfig);
                threadReDoTime.remove();
                return;
            }
            //记录开票失败原因备注,同时发送公告给品牌人员
            this.updateRemarkAndSendNotice(invoiceRecord.getId(),Integer.parseInt(code.toString()),jsonObject.get("msg").toString(),invoiceConfig);
            throw new BaseException(jsonObject.get("msg").toString());
        }
        //如果是同步开票，需要更新发票信息
        this.invoiceSuccess(invoiceRecord.getFlowId(),jsonObject.get("content"));
        //记录发票发送到邮箱的日志
        this.addSendInvoiceEmailLog(invoiceRecord,invoiceRecord.getEmail(),InvoiceRecordConstant.SEND_INVOICE_TYPE_FIRST);
    }

    /**
     * @description: 申请红冲
     * @author: mo.shanyong
     * @date: 2025/4/3 13:33
     * @param: invoiceRecord
     */
    @Override
    public void applyRedChong(InvoiceRecord invoiceRecord) {
        //创建请求参数
        InvoiceConfig invoiceConfig = invoiceConfigService.queryByBrandId(invoiceRecord.getBrandId());
        if (Objects.isNull(invoiceConfig)){
            log.info("获取自动开票配置为空");
            throw new BaseException("申请重开发票失败，请联系客服人员！");
        }
        RedChongBody redChongBody = this.getRedChongBody(invoiceRecord, invoiceConfig);
        String invoiceRequestBody = this.getInvoiceRequestBody(redChongBody, invoiceConfig, InvoiceRecordConstant.INVOICE_API_RED_CHONG_APPLY_SERVICE_ID);
        //申请红冲
        //获取请求头
        Map<String, String> headers = this.getRequestHead(new Date(), invoiceRequestBody, this.getAutoInvoicingToken(invoiceConfig), invoiceConfig.getAppId());
        String response = HttpUtil.httpRequest(invoiceConfig.getRequestHost() + InvoiceRecordConstant.INVOICE_API_RED_CHONG_APPLY_URI, invoiceRequestBody, headers);
        if (StringUtils.isBlank(response)){
            log.info("申请红冲失败，返回结果为空");
            throw new BaseException("申请重开发票失败，请联系客服人员");
        }
        JSONObject jsonObject = JSON.parseObject(response);
        log.info("申请红冲返回结果：{}",JSON.toJSONString(jsonObject));
        Object code = jsonObject.get("code");
        if (Objects.isNull(code) || !Objects.equals(Integer.parseInt(code.toString()), CommonConstant.AUTO_INVOICE_REQUEST_SUCCESS_CODE)){
            //判断是否是因为token过期导致的失败
            if (this.reDo(Integer.parseInt(code.toString()))){
                threadReDoTime.set(1);
                redisService.del( AUTO_INVOICE_KEY + invoiceConfig.getBrandId());
                applyRedChong(invoiceRecord);
                threadReDoTime.remove();
                return;
            }
            log.info("申请红冲失败，返回结果：{}",JSON.toJSONString(jsonObject));
            throw new BaseException(jsonObject.get("msg").toString());
        }
        //成功
        JSONObject content = (JSONObject)jsonObject.get("content");
        invoiceRecord.setRedChongVoteId(content.get("hzfpxxqrdid").toString());
    }

    /**
     * @description: 处理红冲确认单
     * @author: mo.shanyong
     * @date: 2025/4/7 19:47
     * @param: invoiceId 发票id
     * @param: redChongState 红冲确认状态，0-拒绝 1-确认
     */
    @Override
    public void dealRedChong(Integer invoiceId,Integer redChongState) {
        log.info("确认红冲:发票id{},红冲确认单处理状态：{}",invoiceId,redChongState);
        //创建请求参数
        InvoiceRecord invoiceRecord = invoiceRecordDao.queryInvoiceRecordById(invoiceId);
        if (Objects.isNull(invoiceRecord)){
            log.info("获取不到发票信息");
            throw new BaseException("没有获取到发票信息");
        }
        InvoiceConfig invoiceConfig = invoiceConfigService.queryByBrandId(invoiceRecord.getBrandId());
        if (Objects.isNull(invoiceConfig)){
            log.info("获取到自动开票配置为空");
            throw new BaseException("未配置自动开票配置");
        }
        if (StringUtils.isNotBlank(invoiceRecord.getInvoiceNumber())) {
            //申请红冲
            this.applyRedChong(invoiceRecord);
            //确认红冲
            this.confirmRedChong(invoiceRecord, invoiceConfig, redChongState);
        }
        //拒绝红冲后直接返回
        if (Objects.equals(redChongState,InvoiceRecordConstant.RED_CHONG_REFUSE)){
            return;
        }
        //确认红冲后，重开发票
        InvoiceRecord newInvoiceRecord = invoiceRecordDao.queryInvoiceRecordById(invoiceRecord.getNewId());
        this.autoInvoicing(newInvoiceRecord);
    }

    /**
     * @description: 发票发送邮件
     * @author: mo.shanyong
     * @date: 2025/4/3 13:35
     * @param: invoiceRecord
     * @return: com.tbit.uqbike.client.pojo.Result
     */
    @Override
    public void reSendInvoiceEmail(InvoiceRecord invoiceRecord,String receiveEmail) {
        //创建请求参数
        InvoiceConfig invoiceConfig = invoiceConfigService.queryByBrandId(invoiceRecord.getBrandId());
        JSONObject reSendInvoiceEmailBody = this.getReSendInvoiceEmailBody(invoiceRecord, receiveEmail);
        String invoiceRequestBody = this.getInvoiceRequestBody(reSendInvoiceEmailBody, invoiceConfig, InvoiceRecordConstant.INVOICE_API_SEND_EMAIL_SERVICE_ID);
        //获取请求头
        Map<String, String> headers = this.getRequestHead(new Date(), invoiceRequestBody, this.getAutoInvoicingToken(invoiceConfig), invoiceConfig.getAppId());
        String response = HttpUtil.httpRequest(invoiceConfig.getRequestHost() + InvoiceRecordConstant.INVOICE_API_SEND_EMAIL_URI, invoiceRequestBody, headers);
        if (StringUtils.isBlank(response)){
            log.info("申请重发发票到邮箱失败，返回结果为空");
            throw new BaseException("申请重发发票到邮箱失败，请联系客服人员");
        }
        JSONObject jsonObject = JSON.parseObject(response);
        log.info("申请重发发票到邮箱返回结果：{}",JSON.toJSONString(jsonObject));
        Object code = jsonObject.get("code");
        if (Objects.isNull(code) || !Objects.equals(Integer.parseInt(code.toString()), CommonConstant.AUTO_INVOICE_REQUEST_SUCCESS_CODE)){
            //判断是否是因为token过期导致的失败
            if (this.reDo(Integer.parseInt(code.toString()))){
                threadReDoTime.set(1);
                redisService.del( AUTO_INVOICE_KEY + invoiceConfig.getBrandId());
                reSendInvoiceEmail(invoiceRecord,receiveEmail);
                threadReDoTime.remove();
                return;
            }
            log.info("申请重发发票到邮箱失败，返回结果：{}",JSON.toJSONString(jsonObject));
            throw new BaseException(jsonObject.get("msg").toString());
        }
        //记录发票发送到邮箱的日志
        this.addSendInvoiceEmailLog(invoiceRecord,receiveEmail,InvoiceRecordConstant.SEND_INVOICE_TYPE_NEXT);

    }

    /**
     * @description: 开票异步回调
     * @author: mo.shanyong
     * @date: 2025/4/3 13:43
     * @param: notifyBody
     */
    @Override
    public void invoiceNotify(String notifyBody) {
        JSONObject jsonObject = JSONObject.parseObject(notifyBody);
        JSONObject content = JSONObject.parseObject(jsonObject.get("content").toString());
        //发票的申请编号
        String flowId = content.get("fpqqlsh").toString();
        //开票失败
        if (!Objects.equals(Integer.parseInt(jsonObject.get("code").toString()),CommonConstant.AUTO_INVOICE_REQUEST_SUCCESS_CODE)){
            log.info("开票失败，返回错误信息：{}",JSON.toJSONString(content));
            InvoiceRecord invoiceRecord = invoiceRecordDao.getByFlowId(flowId);
            InvoiceConfig invoiceConfig = invoiceConfigService.queryByBrandId(invoiceRecord.getBrandId());
            //更新发票的备注信息,同时发送公告给品牌人员
            String msg = Objects.nonNull(content.get("message")) ? content.get("message").toString() : "自动开票失败，请登录开票系统查看具体原因！";
            this.updateRemarkAndSendNotice(invoiceRecord.getId(),Integer.parseInt(jsonObject.get("code").toString()),msg,invoiceConfig);
            return;
        }
        //开票成功
        this.invoicingSuccess(flowId,content);
    }

    /**
     * @description: 联想企业发票抬头
     * @author: mo.shanyong
     * @date: 2025/4/3 13:54
     * @param: companyName 输入的名字
     * @param: brandId 品牌id
     * @return: javax.json.JsonObject
     */
    @Override
    public List<JSONObject> associateCompany(String companyName,Integer brandId) {
        if (StringUtils.isBlank(companyName) || Objects.isNull(brandId)){
            return new ArrayList<>();
        }
        InvoiceConfig invoiceConfig = invoiceConfigService.queryByBrandId(brandId);
        if (Objects.isNull(invoiceConfig)){
            return new ArrayList();
        }
        //创建请求参数
        JSONObject json = new JSONObject();
        json.put("qymc",companyName);
        String invoiceRequestBody = this.getInvoiceRequestBody(json, invoiceConfig, InvoiceRecordConstant.INVOICE_API_ASSOCIATE_SERVICE_ID);
        Map<String, String> headers = this.getRequestHead(new Date(), invoiceRequestBody, this.getAutoInvoicingToken(invoiceConfig), invoiceConfig.getAppId());
        String response = HttpUtil.httpRequest(invoiceConfig.getRequestHost() + InvoiceRecordConstant.INVOICE_API_ASSOCIATE_URI, invoiceRequestBody, headers);
        if (StringUtils.isBlank(response)){
            log.info("获取联想企业抬头失败，返回结果为空");
            return new ArrayList();
        }
        JSONObject jsonObject = JSON.parseObject(response);
        log.info("获取发票联想抬头，返回结果：{}",JSON.toJSONString(jsonObject));
        Object code = jsonObject.get("code");
        if (Objects.isNull(code) || !Objects.equals(Integer.parseInt(code.toString()), CommonConstant.AUTO_INVOICE_REQUEST_SUCCESS_CODE)){
            log.info("联想企业抬头失败，返回结果：{}",JSON.toJSONString(jsonObject));
            return new ArrayList();
        }
        return JSON.parseArray(jsonObject.get("content").toString(),JSONObject.class);
    }
    /**
     * @description: 自动重新生成发票
     * @author: mo.shanyong
     * @date: 2025/5/30 9:54
     * @param: invoiceId
     */
    @Override
    public void reAutoInvoicing(Integer invoiceId) {
        InvoiceRecord invoiceRecord = invoiceRecordDao.queryInvoiceRecordById(invoiceId);
        if (Objects.isNull(invoiceRecord)){
            throw new BaseException("发票不存在");
        }
        autoInvoicing(invoiceRecord);
    }

    /**
     * @description: 自动开票获取token
     * @author: mo.shanyong
     * @date: 2025/4/2 14:39
     * @param: invoiceConfig
     * @return: java.lang.String
     */
    private String getAutoInvoicingToken(InvoiceConfig invoiceConfig){
        String key = AUTO_INVOICE_KEY + invoiceConfig.getBrandId();
        String token = redisService.get(key);
        if (StringUtils.isNotBlank(token)){//如果存在token说明没过期，直接返回使用
            return token;
        }
        String path = invoiceConfig.getGetTokenUrl();
        String parm = "appId=" + invoiceConfig.getAppId() + "&appScrt=" + invoiceConfig.getAppSecret();
//        log.info("自动开票获取token路径：{}",path);
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Content-Type", "application/x-www-form-urlencoded");
        String response = HttpUtil.httpRequest(path, parm, headers);
        if (StringUtils.isBlank(response)){
            return token;
        }
        JSONObject json = JSON.parseObject(response);
        log.info("自动开票获取token请求返回结果：{}",JSON.toJSONString(json));
        Integer code = (Integer)json.get("code");
        if (!Objects.equals(code,CommonConstant.AUTO_INVOICE_REQUEST_SUCCESS_CODE)){
            log.info("自动开票获取token失败,返回结果为：{}",JSON.toJSONString(json));
            return token;
        }
        //有效时长，单位：秒
        Integer expires = (Integer) json.getJSONObject("result").get("expires");
        long expireTime = 60 * 90;
        if (Objects.nonNull(expires)){//如果是使用请求返回的有效时长，为了防止token过期，则在它返回的时长上减去10分钟
            expireTime = Long.valueOf(expires) - (60 * 10);
        }
        token = (String) json.getJSONObject("result").get("accessToken");
        if (StringUtils.isBlank(token)){
            log.info("自动开票获取到的token为空");
            return token;
        }
        log.info("自动开票获取的token:{},有效期：{} 秒",token,expireTime);

        redisService.add(key,token,expireTime);
        return token;
    }

    /**
     * @description: 获取发送请求的参数
     * @author: mo.shanyong
     * @date: 2025/4/3 11:15
     * @param: requestObject 请求参数
     * @param: invoiceConfig 发票配置
     * @param: invoiceRecord 发票内容
     * @return: java.lang.String
     */
    private String getInvoiceRequestBody(Object requestObject,InvoiceConfig invoiceConfig,String serviceId){
        JSONObject body = new JSONObject();
        body.put("serviceId", serviceId);
        if (Objects.nonNull(invoiceConfig)) {
            body.put("dlzh", invoiceConfig.getTaxBureauAccount());
            body.put("nsrsbh", invoiceConfig.getBrandTaxNumber());
        }
        body.put("content", requestObject);
        return body.toJSONString();
    }

    /**
     * @description: 组装开票信息
     * @author: mo.shanyong
     * @date: 2025/4/2 17:45
     * @param: invoiceRecord 发票信息
     * @param: invoiceConfig 品牌的发票配置
     * @return: com.tbit.uqbike.client.pojo.autoInvoice.AutoInvoiceBody
     */
    private AutoInvoiceBody getAutoInvoiceBody(InvoiceRecord invoiceRecord,InvoiceConfig invoiceConfig){
        List<InvoiceOrderBandMoney> invoiceOrderBandMoneyList = invoiceRecordDao.selectBandOrder(invoiceRecord.getId());
        AutoInvoiceBody autoInvoiceBody = new AutoInvoiceBody();
        autoInvoiceBody.setFpqqlsh(invoiceRecord.getFlowId());
        autoInvoiceBody.setXfmc(invoiceConfig.getBrandCompanyName());
        autoInvoiceBody.setNsrsbh(invoiceConfig.getBrandTaxNumber());
        autoInvoiceBody.setGfzrrbs(Objects.equals(invoiceRecord.getTitleType(),InvoiceRecordConstant.INVOICE_TITLE_TYPE_COMPANY) ? "N" : "Y");
        autoInvoiceBody.setGfmc(invoiceRecord.getCompanyTitle());
        autoInvoiceBody.setGfsh(invoiceRecord.getCompanyTaxNumber());
        autoInvoiceBody.setXfdz(invoiceConfig.getBrandAddress());
        autoInvoiceBody.setXfkhh(invoiceConfig.getBrandAccountBankName());
        autoInvoiceBody.setXflxdh(invoiceConfig.getBrandAccountPhone());
        autoInvoiceBody.setXfyhzh(invoiceConfig.getBrandAccount());
        autoInvoiceBody.setMxList(this.getMxList(invoiceOrderBandMoneyList,invoiceConfig.getBrandTaxNumber()));
        autoInvoiceBody.setSpExt(this.getSpExt(invoiceRecord,invoiceConfig));
        return autoInvoiceBody;

    }

    /**
     * @description: 获取开票的订单内容集合
     * @author: mo.shanyong
     * @date: 2025/4/3 9:34
     * @param: invoiceOrderBandMoneyList
     * @param: companyTaxNumber
     * @return: java.util.List<com.tbit.uqbike.client.pojo.autoInvoice.OrderDetail>
     */
    private List<OrderDetail> getMxList(List<InvoiceOrderBandMoney> invoiceOrderBandMoneyList,String companyTaxNumber){
        List<OrderDetail> orderDetailList = new ArrayList<>();
        for (InvoiceOrderBandMoney invoiceOrderBandMoney : invoiceOrderBandMoneyList) {
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setJe(String.valueOf(invoiceOrderBandMoney.getMoney()));
            orderDetail.setSpmc("骑行订单"+invoiceOrderBandMoney.getOrderNo());
            orderDetail.setNsrsbh(companyTaxNumber);
            double mul = NumberUtil.mul(invoiceOrderBandMoney.getMoney().doubleValue(), Double.parseDouble(orderDetail.getSl()));
            BigDecimal bigDecimal = new BigDecimal(mul);
            orderDetail.setSe(String.valueOf(bigDecimal.setScale(2, RoundingMode.HALF_UP)));
            orderDetail.setSpbm(spbm);
            orderDetailList.add(orderDetail);
        }
        return orderDetailList;
    }
    /**
     * @description: 返回拓展信息
     * @author: mo.shanyong
     * @date: 2025/4/3 10:32
     * @param: invoiceRecord
     * @param: invoiceConfig
     * @return: com.tbit.uqbike.client.pojo.autoInvoice.SpExt
     */
    private SpExt getSpExt(InvoiceRecord invoiceRecord,InvoiceConfig invoiceConfig){
        SpExt spExt = new SpExt();
        spExt.setHddz(invoiceConfig.getNotifyUrl());
        spExt.setYxdz(invoiceRecord.getEmail());
        return spExt;
    }
    /**
     * @description: 获取红冲申请参数
     * @author: mo.shanyong
     * @date: 2025/4/3 16:19
     * @param: invoiceRecord
     * @param: invoiceConfig
     * @return: com.tbit.uqbike.client.pojo.autoInvoice.RedChongBody
     */
    private RedChongBody getRedChongBody(InvoiceRecord invoiceRecord,InvoiceConfig invoiceConfig){
        RedChongBody redChongBody = new RedChongBody();
        redChongBody.setXfsh(invoiceConfig.getBrandTaxNumber());
        //税额
        double taxMoney = NumberUtil.mul(invoiceRecord.getInvoiceAmount().doubleValue(), InvoiceRecordConstant.TAX_RATE);
        redChongBody.setHzcxje("-" + (invoiceRecord.getInvoiceAmount() - taxMoney));
        redChongBody.setHzcxse("-" + taxMoney);
        redChongBody.setYkprq(DateTimeUtil.DateTimeToString(invoiceRecord.getApplyTime()));
        redChongBody.setYfphm(invoiceRecord.getInvoiceNumber());
        return redChongBody;
    }

    /**
     * @description: 获取重发邮件请求的传递参数
     * @author: mo.shanyong
     * @date: 2025/4/3 17:25
     * @param: invoiceRecord 发票信息
     * @param: receiveEmail 接收邮件
     * @return: com.alibaba.fastjson.JSONObject
     */
    private JSONObject getReSendInvoiceEmailBody(InvoiceRecord invoiceRecord,String receiveEmail){
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("email",receiveEmail);
        jsonObject.put("fphm",invoiceRecord.getInvoiceNumber());
        return jsonObject;
    }
    /**
     * @description: 获取发票接口的请求头参数
     * @author: mo.shanyong
     * @date: 2025/4/7 10:05
     * @param: date 时间
     * @param: requestBody 请求体参数
     * @param: token 数族的请求token
     * @param: appID 配置的应用ID
     * @return: java.util.Map<java.lang.String, java.lang.String>
     */

    private Map<String, String> getRequestHead(Date date,String requestBody,String token,String appID){
        String dateTimeStr = String.valueOf(date.getTime());
        String sign = Base64.encodeBase64String(DigestUtils.md5Hex(requestBody + dateTimeStr + token).getBytes());
        Map<String, String> headers = new HashMap<>();
        headers.put("AppId", appID);
        headers.put("Date", dateTimeStr);
        headers.put("Content-MD5", sign);
        headers.put("Content-Type", "application/json");
        return headers;
    }
    /**
     * @description: 确认红冲发送请求
     * @author: mo.shanyong
     * @date: 2025/4/7 19:38
     * @param: invoiceRecord
     * @param: invoiceConfig
     */
    private void confirmRedChong(InvoiceRecord invoiceRecord,InvoiceConfig invoiceConfig,Integer redChongState){
        //封装参数
        JSONObject json = new JSONObject();
        //红字发票信息确认单id
        json.put("hzfpxxqrdid",invoiceRecord.getRedChongVoteId());
        //销售方纳税人识别号
        json.put("xsfnsrsbh",String.valueOf(invoiceConfig.getBrandTaxNumber()));
        //0-拒绝 1-确认
        json.put("qrlx",String.valueOf(redChongState));
        String invoiceRequestBody = this.getInvoiceRequestBody(json, invoiceConfig, InvoiceRecordConstant.INVOICE_API_RED_CHONG_CONFIRM_SERVICE_ID);
        Map<String, String> headers = this.getRequestHead(new Date(), invoiceRequestBody, this.getAutoInvoicingToken(invoiceConfig), invoiceConfig.getAppId());
        String response = HttpUtil.httpRequest(invoiceConfig.getRequestHost() + InvoiceRecordConstant.INVOICE_API_RED_CHONG_CONFIRM_URI, invoiceRequestBody, headers);
        if (StringUtils.isBlank(response)){
            log.info("红字发票确认返回结果为空");
            throw new BaseException("红冲失败，请联系客服人员。");
        }
        JSONObject jsonObject = JSON.parseObject(response);
        log.info("红字发票确认，返回结果：{}",JSON.toJSONString(jsonObject));
        Object code = jsonObject.get("code");
        if (Objects.isNull(code) || (!Objects.equals(Integer.parseInt(code.toString()), CommonConstant.AUTO_INVOICE_REQUEST_SUCCESS_CODE) &&
                Objects.nonNull(jsonObject.get("msg")) && !Objects.equals(CommonConstant.AUTO_INVOICE_TEST_ERROR_MSG,jsonObject.get("msg").toString()))
        ){
            //判断是否是因为token过期导致的失败
            if (this.reDo(Integer.parseInt(code.toString()))){
                threadReDoTime.set(1);
                redisService.del( AUTO_INVOICE_KEY + invoiceConfig.getBrandId());
                confirmRedChong(invoiceRecord,invoiceConfig,redChongState);
                threadReDoTime.remove();
                return;
            }
            log.info("红字发票确认失败，返回结果：{}",JSON.toJSONString(jsonObject));
            throw new BaseException("红冲失败，请联系客服人员。");
        }
        //更新红冲单id
        InvoiceRecord update = new InvoiceRecord();
        update.setRedChongVoteId(invoiceRecord.getRedChongVoteId());
        update.setId(invoiceRecord.getId());
        invoiceRecordDao.updateCheckNull(update);
    }

    /**
     * @description: 发送
     * @author: mo.shanyong
     * @date: 2025/4/9 14:49
     * @param: invoiceRecord 发票
     * @param: email 邮箱
     * @param: sendType 发票发送类型：0-首次申请时发送；1-非首次申请时发送
     */
    private void addSendInvoiceEmailLog(InvoiceRecord invoiceRecord,String email,Integer sendType){
        SendInvoiceLog sendInvoiceLog = new SendInvoiceLog();
        sendInvoiceLog.setInvoiceRecordId(invoiceRecord.getId());
        sendInvoiceLog.setSendType(sendType);
        sendInvoiceLog.setReceiveEmail(email);
        sendInvoiceLogService.insertCheckNull(sendInvoiceLog);
    }
    /**
     * @description: 封装公告数据
     * @author: mo.shanyong
     * @date: 2025/6/3 13:46
     * @param: msg
     * @param: invoiceConfig
     * @return: com.tbit.uqbike.client.pojo.vo.NoticeVO
     */
    private NoticeVO getNoticeVO(String msg,InvoiceConfig invoiceConfig){
        NoticeVO noticeVO = new NoticeVO();
        noticeVO.setAuthor("系统");
        noticeVO.setIntroduction("自动开票失败,开票系统提示：" + msg);
        noticeVO.setTitle("自动开票失败");
        //系统公告
        noticeVO.setType(0);
        //有效期1年
        noticeVO.setStartTime(DateTimeUtil.getNowTime());
        noticeVO.setEndTime(DateTimeUtil.getTimeStrByLocalDateTime(LocalDateTime.now().plusYears(1)));
        //只在管理端、运维端生效
        noticeVO.setPlatformList(Collections.singletonList(com.tbit.common.constant.CommonConstant.NOTICE_MANAGER_PLATFORM));
        noticeVO.setAccountIdList(Collections.singletonList(invoiceConfig.getBrandId()));
        //发给品牌账号
        NoticeAppointType noticeAppointType = new NoticeAppointType();
        noticeAppointType.setType(1);
        noticeAppointType.setPlatform(com.tbit.common.constant.CommonConstant.NOTICE_MANAGER_PLATFORM);
        noticeAppointType.setAppointUserPhone("0");
        noticeVO.setAppointUserTypeList(Collections.singletonList(noticeAppointType));
        StringBuilder content = new StringBuilder();
        content.append("<div style=\"font-size: 14px; color: #333333;\">" +
                "  <p>您好！自动开票系统异常提示：")
                .append(msg)
                .append("，导致用户申请的开票未能成功。为保障业务正常推进，请确保已").append("<a href=\"").append(loginUrl).append("\" target=\"_blank\">登录开票系统</a>")
                .append("，现提供两种处理方式供您选择：</p>" +
                "<br />" +
                "<p>1、自动重开：在开票管理中点击【自动重开】，继续执行未完成的开票任务。</p>" +
                "<br />" +
                "<p>2、人工开票：若您希望自行处理开票事宜，也可选择进入开票管理页面，手动完成发票开具。</p>" +
                "<br />" +
                "<p><a href=\"javascript:void(0);\" onclick=\"window.vueRouter.push('/admin/userManager/invoicingManagement')\">开票管理>></a></p>" +
                "</div>");
        noticeVO.setContent(content.toString());
        return noticeVO;
    }

    /**
     * @description: 开票失败，更新开票备注,发送自动开票失败通知给品牌人员
     * @author: mo.shanyong
     * @date: 2025/6/3 14:18
     * @param: invoiceId
     * @param: msg
     */
    private void updateRemarkAndSendNotice(Integer invoiceId,Integer code,String msg,InvoiceConfig invoiceConfig){
        InvoiceRecord update = new InvoiceRecord();
        update.setId(invoiceId);
        msg = InvoiceRecordConstant.getErrorMsg(code, msg);
        update.setInvoicingDetail("自动开票失败，开票系统提示：" + msg);
        invoiceRecordDao.updateCheckNull(update);
        //发送开票失败错误公告
        noticeService.insertCheckNull(this.getNoticeVO(msg,invoiceConfig));
    }
    /**
     * @description: 判断是否重做
     * @author: mo.shanyong
     * @date: 2025/6/4 15:52
     * @param: code
     * @return: boolean
     */
    private boolean reDo(Integer code){
        return Objects.equals(Integer.parseInt(code.toString()), CommonConstant.AUTO_INVOICE_TOKEN_OUT_TIME_CODE) && Objects.isNull(threadReDoTime.get());
    }

    /**
     * @description: 开票成功，更新发票信息
     * @author: mo.shanyong
     * @date: 2025/6/6 16:17
     * @param: flowId
     * @param: content
     */
    private void invoicingSuccess(String flowId,JSONObject content){
        InvoiceRecord update = new InvoiceRecord();
        update.setFlowId(flowId);
        update.setInvoiceTime(new Date());
        update.setInvoiceNumber(content.get("fphm").toString());
        update.setStatus(InvoiceRecordConstant.STATUS_SUCCESS);
        update.setUrl(content.get("pdfUrl").toString());
        update.setInvoicingDetail("自动开票成功");
        invoiceRecordDao.updateCheckNull(update);
    }
    /**
     * @description: 同步开票成功后更新发票信息
     * @author: mo.shanyong
     * @date: 2025/6/6 16:40
     * @param: flowId
     * @param: object
     */
    private void invoiceSuccess(String flowId,Object object){
        if (Objects.isNull(object)){
            return;
        }
        JSONObject content = (JSONObject) object;
        if (Objects.isNull(content.get("fphm"))){
            return;
        }
        this.invoicingSuccess(flowId,content);

    }
}
